package top.lixunda.ecommerce.server.user.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;

import java.util.Optional;
import java.util.Date;
import java.util.UUID;

/**
 * @author Xumda
 * @version time:2019/11/22 13:46
 */
@SuppressWarnings({"WeakerAccess", "unused"})
@Slf4j
public class JwtTokenUtil {
    public static final String TOKEN_HEADER = "gtboot";
    public static final String TOKEN_PREFIX = "gtboot ";

    /**
     * 密钥
     */
    private static final String SECRET = "jwt_secret_gtboot";

    /**
     * 默认签发人
     */
    private static final String ISS = "commerce";

    /**
     * 过期时间是 1800 秒
     */
    private static final long EXPIRATION = 10 * 24 * 60 * 50L;

    /**
     * 受众
     */
    private static final String AUDIENCE = "default";

    /**
     * 创建 token, 过期时间默认10天
     *
     * @param issuer  签发人
     * @param subject 主体,即用户信息的JSON
     * @return 创建的token
     */
    public static String createToken(String issuer, String subject) {
        return createToken(issuer, subject, EXPIRATION);
    }

    /**
     * 创建 token
     *
     * @param issuer     签发人
     * @param subject    主体,即用户信息的JSON
     * @param expiration 有效时间(秒)
     * @return 创建的token
     */
    public static String createToken(String issuer, String subject, long expiration) {
        return createToken(issuer, subject, expiration, null);
    }

    /**
     * 创建 token
     *
     * @param issuer     签发人
     * @param subject    主体,即用户信息的JSON
     * @param expiration 有效时间(秒)
     * @param claims     自定义参数
     * @return 创建的token
     */
    public static String createToken(String issuer, String subject, long expiration, Claims claims) {
        return Jwts.builder()
                // JWT_ID：是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
                .setId(UUID.randomUUID().toString())
                // 签名算法以及密匙
                .signWith(SignatureAlgorithm.HS512, SECRET)
                // 自定义属性
                .setClaims(claims)
                // 主题：代表这个JWT的主体，即它的所有人，这个是一个json格式的字符串，可以存放什么userId，roleId之类的，作为什么用户的唯一标志。
                .setSubject(subject)
                // 受众
                .setAudience(AUDIENCE)
                // 签发人
                .setIssuer(Optional.ofNullable(issuer).orElse(ISS))
                // 签发时间
                .setIssuedAt(new Date())
                // 过期时间
                .setExpiration(new Date(System.currentTimeMillis() + (expiration > 0 ? expiration : EXPIRATION) * 1000))
                .compact();
    }

    /**
     * 从 token 中获取主题信息
     *
     * @param token 本类生成的token
     * @return 主题信息
     */
    public static String getProperties(String token) {
        Claims claims = getTokenBody(token);
        if (claims != null) {
            return claims.getSubject();
        }
        return "";
    }


    /**
     * 校验是否过期
     *
     * @param token 本类生成的token
     * @return true 过期 false 未过期
     */
    public static boolean isExpiration(String token) {
        Claims claims = getTokenBody(token);
        if (claims != null) {
            return claims.getExpiration().before(new Date());
        }
        return true;
    }

    /**
     * 获得 token 的 body
     *
     * @param token 本类生成的token
     * @return 获取body
     */
    private static Claims getTokenBody(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(SECRET)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            log.warn("错误的token，解析错误 {}", e.getMessage());
            return null;
        }
    }
}
